namespace YM {
    export class ResInfo {
        name: string;
        path: string;
        type: new()=>any;
        res:any;
        constructor(name:string,path:string,type:new()=>any,res){
            this.name=name;
            this.path=path;
            this.type=type;
            this.res=res;
        }
    }
    
    export class Resource {
        private resDict: Map<{ new() }, Map<string, ResInfo>> = new Map<{ new()}, Map<string, ResInfo>>();
        public load(url: string, type: typeof cc.Asset, progressCallback: (completedCount: number, totalCount: number, item: any) => void, completeCallback: ((error: Error, resource: any) => void)|null){
            cc.loader.loadRes(url,type,progressCallback,completeCallback);
        }      
        public async loadAsync<T extends cc.Asset>(url:string,type?:new()=>T,progressCallback?: (completedCount: number, totalCount: number, item: any) => void){
            return new Promise<T>(resolve=>{
                if(!type&&!progressCallback){
                    cc.loader.loadRes(url,(err,res)=>{
                        this.addResInfo(res,url);
                        resolve(res);
                    });
                }
                else if(!type&&progressCallback){
                    cc.loader.loadRes(url,progressCallback,(err,res)=>{
                        this.addResInfo(res,url);
                        resolve(res);
                    });
                }
                else if(type&&!progressCallback){
                    cc.loader.loadRes(url,type as any,(err,res)=>{
                        this.addResInfo(res,url);
                        resolve(res);
                    });
                }
                else if(type&&progressCallback){
                    cc.loader.loadRes(url,type as any,progressCallback,(err,res)=>{
                        this.addResInfo(res,url);
                        resolve(res);
                    });
                }
            });
        }
        public async loadArrAsync<T extends cc.Asset>(urls:string[],progressCallback?: (completedCount: number, totalCount: number, item: any) => void){
            return new Promise<T[]>(resolve=>{
                if(progressCallback){
                    cc.loader.loadResArray(urls,progressCallback,(err,res)=>{
                        res.forEach((value,index) => {
                            this.addResInfo(value,urls[index]);
                        });
                        resolve(res);
                    });
                }
                else if(!progressCallback){
                    cc.loader.loadResArray(urls,(err,res)=>{
                        res.forEach((value,index) => {
                            this.addResInfo(value,urls[index]);
                        });
                        resolve(res);
                    });
                }
            });
        }
        public getRes<T extends cc.Asset>(type:{new():T},name:string):T{
            let resDic=this.resDict.get(type);
            if(!resDic){
                return null;
            }
            let resInfo=resDic.get(name);
            if(!resInfo){
                return null;
            }

            return resInfo.res as T;
        }
        public getResByPath<T extends cc.Asset>(url:string,type?:{new():T}){
           return cc.loader.getRes(url,type) as T;
        }
        private addResInfo(res:cc.Asset,path:string){
            let resInfo=new ResInfo(res.name,path,(<any>res).__proto__.constructor,res);
            resInfo.name=res.name;
            resInfo.path=path;
            resInfo.type=(<any>res).__proto__.constructor;
            let dic=this.resDict.get(resInfo.type);
            if(dic==null){
                dic=new Map<string,ResInfo>();
                this.resDict.set(resInfo.type,dic);
            }
            dic.set(res.name,resInfo);
        }
        public setRes<T>(type:new()=>T,res,resName:string,path?:string){
            let resDic = this.resDict.get(type);
            if (resDic == null) {
                resDic=new Map<string,ResInfo>();
                this.resDict.set(type,resDic);
            }
            let resInfo=new ResInfo(resName,path,type,res);
            resDic.set(resName,resInfo);
        }
    }
}